#include "stdafx.h"
#include "GrabDemo.h"
#include "DlgNodeList.h"
#include "cameraframe.h"
#include <convert.h>
#include ".\dlgnodelist.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CDlgNodeList *pDlgNodeList;

/////////////////////////////////////////////////////////////////////////////
// CDlgNodeList Dialogfeld

CDlgNodeList::CDlgNodeList(CWnd* pParent /*=NULL*/)
	: CDialog(CDlgNodeList::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDlgNodeList)
	//}}AFX_DATA_INIT
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

        m_MsgCnt=0;
        m_LogEnabled=TRUE;
        m_Memory=0;
        m_MsgsInFlight=0;
        m_MsgOverflow=FALSE;
        
        // Init our convert module
        InitTables();

        // Set global pointer
        pDlgNodeList=this;
}

void CDlgNodeList::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDlgNodeList)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDlgNodeList, CDialog)
	//{{AFX_MSG_MAP(CDlgNodeList)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_CLEARLOG, OnClearLog)
	ON_WM_CLOSE()
        ON_MESSAGE(WM_LOGMSG, OnLogMsg)
        ON_MESSAGE(WM_FGNOTIFY, OnFgNotify)
	ON_BN_CLICKED(IDB_CONNECT, OnConnect)
	ON_LBN_DBLCLK(IDL_DEVICES, OnDblclkDevices)
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDlgNodeList Nachrichten-Handler

BOOL CDlgNodeList::OnInitDialog()
{
  RECT    Rect;
  UINT32  Result;
  FGINIT  Arg;
  char Buffer[32];

  // Call dialogs initialization
  CDialog::OnInitDialog();

  if(FGGetHostLicenseRequest(Buffer,sizeof(Buffer))==FCE_NOERROR)
   GetDlgItem(IDE_HOST)->SetWindowText(Buffer);

  SetIcon(m_hIcon, TRUE);	
	
  GetDlgItem(IDE_MEMORY)->SetWindowText("0.00");
  
  // Always put window to upper left corner of desktop
  GetWindowRect(&Rect);
  MoveWindow(10,10,Rect.right-Rect.left,Rect.bottom-Rect.top);
  
  // Init our grabber module
  memset(&Arg,0,sizeof(FGINIT));
  
  Arg.hWnd=m_hWnd;
  Arg.Msg=WM_FGNOTIFY;
  
  // Let's post Iso notification directly to a window
  Arg.Flags=FGIF_ISOCONTEXTISHWND;
        
  Result=FGInitModule(&Arg);
  if(Result!=FCE_NOERROR)
   LogResult("FGInit",Result);

  return TRUE;
}

void CDlgNodeList::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this);

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

HCURSOR CDlgNodeList::OnQueryDragIcon()
{
  return (HCURSOR) m_hIcon;
}

/////////////////////////////////////////////////////////////////////////////
// Handle WM_LOGMSG message.

LRESULT CDlgNodeList::OnLogMsg(WPARAM wParam,LPARAM)
{
  CListBox *pListBox;
  char     *pMsg;

  pMsg=(char*)wParam;
  if(pMsg)
  {
    pListBox=(CListBox*)GetDlgItem(IDL_LOG);
    if(pListBox)
    {
      pListBox->AddString(pMsg);
      pListBox->SetCurSel(pListBox->GetCount()-1);
    }
    delete pMsg;

    m_CriticalSection.Lock();
    if(m_MsgsInFlight && --m_MsgsInFlight==0)
     m_MsgOverflow=FALSE;
    m_CriticalSection.Unlock();
  }

  return 0;
}

/////////////////////////////////////////////////////////////////////////////
// Log a string message and an additional value.
// To avoid a deadlock situation we POST a message to our window.

void CDlgNodeList::LogMessage(char* pMsg,DWORD lParam) 
{
  char *pBuf;

  if(m_LogEnabled && !m_MsgOverflow)
  {
    // Check messages in flight
    m_CriticalSection.Lock();

    // Allocate a buffer
    pBuf=new char[MAXMSGLENGTH];
    if(pBuf)
    {
      if(m_MsgsInFlight>=MAXMSGSINFLIGHT)
      {
        strcpy(pBuf,"E: Messageoverflow...");
        m_MsgOverflow=TRUE;
      }
      else
      {
        wsprintf(pBuf,"%d: %s",++m_MsgCnt,pMsg);
      }

      PostMessage(WM_LOGMSG,(LPARAM)pBuf,lParam);
    } 

    m_CriticalSection.Unlock();
  }
}

/////////////////////////////////////////////////////////////////////////////
// Check a result (32 Bit).

void CDlgNodeList::CheckResult(char* pFunction,DWORD Result) 
{
  char cbuf[200];

  if(Result!=FCE_NOERROR)
  {
    wsprintf(cbuf,"E: CFG::%s=%d",pFunction,Result);
    LogMessage(cbuf);
  }
}

/////////////////////////////////////////////////////////////////////////////
// Log a result (32 Bit).

void CDlgNodeList::LogResult(char* pFunction,DWORD Result) 
{
  char cbuf[200];

  wsprintf(cbuf,"<%s> returned %d",pFunction,Result);
  LogMessage(cbuf);
}

/////////////////////////////////////////////////////////////////////////////
// Log a DWORD.

void CDlgNodeList::LogDWORD(char* pName,DWORD Value,BOOL Hex) 
{
  char cbuf[200];
                                   
  if(Hex)
   wsprintf(cbuf,"%s=0x%lX",pName,Value);
  else
   wsprintf(cbuf,"%s=%d",pName,Value);

  LogMessage(cbuf);
}

/////////////////////////////////////////////////////////////////////////////
// Clear log window.

void CDlgNodeList::OnClearLog() 
{
  CListBox *pListBox;

  pListBox=(CListBox*)GetDlgItem(IDL_LOG);
  if(pListBox)
   pListBox->ResetContent();
  m_MsgCnt=0;
}

/////////////////////////////////////////////////////////////////////////////
// Reaction on close window.

void CDlgNodeList::OnClose() 
{
  CListBox   *pList;
  CAMERAINFO *pCameraInfo;
  UINT32      ListCnt,i;

  // Return all cameras
  pList=(CListBox*)GetDlgItem(IDL_DEVICES);
  ListCnt=pList->GetCount();
  for(i=0;i<ListCnt;i++)
  {
    pCameraInfo=(CAMERAINFO*)pList->GetItemDataPtr(i);
    if(pCameraInfo)
    {
      if(pCameraInfo->pCameraFrame)
       pCameraInfo->pCameraFrame->Stop();

      delete pCameraInfo;
    }  
  }

  // Exit our frame grabber module (Init is called in InitDialog)
  FGExitModule();

  PostQuitMessage(0);
  CDialog::OnClose();
}

/////////////////////////////////////////////////////////////////////////////
// Report memory usage.

void CDlgNodeList::ReportMemoryUsage(long Memory)
{
  char cbuf[32];

  m_Memory+=Memory;

  sprintf(cbuf,"%.2lf",(double)m_Memory/(double)(1024.0*1024.0));
  GetDlgItem(IDE_MEMORY)->SetWindowText(cbuf);
}

/////////////////////////////////////////////////////////////////////////////
// Make name for a device.

void CDlgNodeList::GetDisplayName(CAMERAINFO *pCameraInfo,char *pBuf)
{
  wsprintf(pBuf,"%s",pCameraInfo->DeviceName);
}

/////////////////////////////////////////////////////////////////////////////
// Add a new node to our list.

void CDlgNodeList::AddNode(FGNODEINFO *pInfo)
{
  CAMERAINFO   *pCameraInfo;
  CListBox     *pList;
  UINT32        Result;
  CFGCamera     FGCamera;
  int           Ix;
  char          DisplayName[160];

  // Create new camera info
  pCameraInfo=new CAMERAINFO;
  if(pCameraInfo)
  {
    pCameraInfo->Busy=pInfo->Busy;
    pCameraInfo->Guid=pInfo->Guid;
    pCameraInfo->NodeId=pInfo->NodeId;
    pCameraInfo->pCameraFrame=NULL;

    // Always limit speed for informational connect
    FGCamera.SetParameter(FGP_PHYSPEED,PS_100MBIT);

    // Connect to get further information
    Result=FGCamera.Connect(&pInfo->Guid,NULL);
    if(Result==FCE_NOERROR)
    {
      // Check busy status
      if(!pCameraInfo->Busy)
       pCameraInfo->DeviceName[0]=' ';
      else
       pCameraInfo->DeviceName[0]='*';
         
      FGCamera.GetDeviceName(pCameraInfo->DeviceName+1,
                               sizeof(pCameraInfo->DeviceName)-1);
      FGCamera.Disconnect();

      GetDisplayName(pCameraInfo,DisplayName);
      pList=(CListBox*)GetDlgItem(IDL_DEVICES);
      Ix=pList->AddString(DisplayName);
      pList->SetItemDataPtr(Ix,pCameraInfo);
    }
    else
    {
      if(Result==HALER_BUSY)
      {
        // We cannot connect so display a busy entry without a camer info
        wsprintf(DisplayName,"*Busy Device (GUID: 0x%08X%08X)",pInfo->Guid.High,pInfo->Guid.Low); 
        pList=(CListBox*)GetDlgItem(IDL_DEVICES);
        pList->AddString(DisplayName);
      }
      else
      {
        // Display error code
        CheckResult("Connect",Result);
      }
      
      delete pCameraInfo;
    }  
  }
}

/////////////////////////////////////////////////////////////////////////////
// Called when frame from camera is closing.

void CDlgNodeList::OnFrameClosing(CAMERAINFO *pCameraInfo)
{
  // Remove in camera info from specific node
  pCameraInfo->pCameraFrame=NULL;
  
  // Rebuild node list to check busy state
  OnNodelistChanged();
}

/////////////////////////////////////////////////////////////////////////////
// Remove node from our list.

void CDlgNodeList::RemoveNode(UINT32 Ix)
{
  CAMERAINFO *pCameraInfo;
  CListBox   *pList;

  pList=(CListBox*)GetDlgItem(IDL_DEVICES);
  pCameraInfo=(CAMERAINFO*)pList->GetItemDataPtr(Ix);
  if(pCameraInfo)
  {
    // Remove window
    if(pCameraInfo->pCameraFrame)
     pCameraInfo->pCameraFrame->Stop();

    // Delete CameraInfo (call destructor from CFGCamera)
    delete pCameraInfo;
  }
  
  // Remove entry in list box
  pList->DeleteString(Ix);
}

/////////////////////////////////////////////////////////////////////////////
// Enable or disable existing node.

void CDlgNodeList::EnableNode(UINT32 Ix,BOOL Enable)
{
  CAMERAINFO *pCameraInfo;
  CListBox   *pList;

  pList=(CListBox*)GetDlgItem(IDL_DEVICES);
  pCameraInfo=(CAMERAINFO*)pList->GetItemDataPtr(Ix);
  if(pCameraInfo)
  {
    if(Enable)
     pCameraInfo->DeviceName[0]=' ';
    else
     pCameraInfo->DeviceName[0]='*';

    pList->DeleteString(Ix);
    pList->InsertString(Ix,pCameraInfo->DeviceName);

    // Set info pointer!
    pList->SetItemDataPtr(Ix,pCameraInfo);
  }
}

/////////////////////////////////////////////////////////////////////////////
// Node list has changed.

void CDlgNodeList::OnNodelistChanged()
{
  FGNODEINFO  NodeInfo[32];
  UINT32      NodeCnt,i,j,ListCnt,Ix;
  UINT32      Result;
  CListBox   *pList;
  CAMERAINFO *pCameraInfo;
  BOOL        MustRemove;

  Result=FGGetNodeList(NodeInfo,sizeof(NodeInfo)/sizeof(FGNODEINFO),&NodeCnt);
  if(Result!=FCE_NOERROR)
   LogResult("FGGetNodeList",Result);
 
  if(Result==FCE_NOERROR)
  {
    pList=(CListBox*)GetDlgItem(IDL_DEVICES);
    ListCnt=pList->GetCount();

    // Step through nodes from our list box and synchronize with new node list
    Ix=0;
    for(i=0;i<ListCnt;i++)
    {
      MustRemove=TRUE;
      pCameraInfo=(CAMERAINFO*)pList->GetItemDataPtr(Ix);
      
      // Did we ever connect to this device successful?
      if(pCameraInfo)
      {
        // Go through new list of reported nodes
        for(j=0;j<NodeCnt;j++)
        {
          // Compare GUID of device with GUID of list box entry
          if(NodeInfo[j].Guid.High && NodeInfo[j].Guid.Low &&
             !memcmp(&NodeInfo[j].Guid,&pCameraInfo->Guid,sizeof(UINT32HL)))
          {
            // We found it in our list box, so make inactive in node list
            NodeInfo[j].Guid.High=0;
            NodeInfo[j].Guid.Low=0;
            MustRemove=FALSE;
            
            // If we are not connected we have to check busy status
            if(!pCameraInfo->pCameraFrame)
            {
              // Store busy information
              pCameraInfo->Busy=NodeInfo[j].Busy;
              
              // If busy we display an asteriks
              if(NodeInfo[j].Busy)
               EnableNode(Ix,FALSE);
              else
               EnableNode(Ix,TRUE); 
            }
            break;
          }
        }
      }  

      // Do we have to remove from list?
      if(MustRemove)
       RemoveNode(Ix);
      else
       Ix++;
    }

    // Add new cameras
    for(i=0;i<NodeCnt;i++)
     if(NodeInfo[i].Guid.High || NodeInfo[i].Guid.Low)
      AddNode(&NodeInfo[i]);
  }
}

/////////////////////////////////////////////////////////////////////////////
// Frame grabber notification.

LRESULT CDlgNodeList::OnFgNotify(WPARAM wParam,LPARAM lParam)
{
  // See what happened
  switch(wParam)
  {
    case WPARAM_NODELISTCHANGED:
     OnNodelistChanged();
     break;

    case WPARAM_ERROR:
     LogDWORD("E: Ored Errorflags",(DWORD)lParam,TRUE);
     break;

    case WPARAM_FRAMESREADY:
     // Message is sent to our camera frame directly!
     LogDWORD("I: Frames ready",0,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD0:
     LogDWORD("E: Errorflags Card0",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD1:
     LogDWORD("E: Errorflags Card1",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD2:
     LogDWORD("E: Errorflags Card2",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD3:
     LogDWORD("E: Errorflags Card3",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD4:
     LogDWORD("E: Errorflags Card4",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD5:
     LogDWORD("E: Errorflags Card5",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD6:
     LogDWORD("E: Errorflags Card6",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD7:
     LogDWORD("E: Errorflags Card7",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD8:
     LogDWORD("E: Errorflags Card8",(DWORD)lParam,TRUE);
     break;

    case WPARAM_ERRORFLAGSCARD9:
     LogDWORD("E: Errorflags Card9",(DWORD)lParam,TRUE);
     break;

    case WPARAM_BUSRESET:
     LogDWORD("I: Busreset-CardMask",(DWORD)lParam,TRUE);
     break;
  }

  return 0;
}

/////////////////////////////////////////////////////////////////////////////
// Connect with camera and create a camera frame.

void CDlgNodeList::OnConnect() 
{
  CListBox        *pList;
  int              Ix;
  CAMERAINFO      *pCameraInfo;
  CCameraFrame    *pCameraFrame;
  RECT             DlgRect;

  // Get current selection in the device list
  pList=(CListBox*)GetDlgItem(IDL_DEVICES);
  Ix=pList->GetCurSel();
  if(Ix==-1)
   return;

  // Get camera info
  pCameraInfo=(CAMERAINFO*)pList->GetItemDataPtr(Ix);
  
  // Return if no info available or CameraFrame already visible.
  // If we don't want double connects we should regard Busy state. 
  if(!pCameraInfo /*|| pCameraInfo->Busy*/ || pCameraInfo->pCameraFrame)
   return;

  // Update speed setting and create frame window
  pCameraInfo->LimitSpeed=((CButton*)GetDlgItem(IDB_LIMITSPEED))->GetCheck();
  pCameraFrame=new CCameraFrame(pCameraInfo);
  if(!pCameraFrame)
  {
    LogMessage("Not enough memory");
    return;
  } 

  // Create frame windows for this camera
  GetWindowRect(&DlgRect);
  if(!pCameraFrame->Start(DlgRect.right+1,DlgRect.top))
  {
    // Must delete object if error
    delete pCameraFrame;
    return;
  }
  
  // Link both together
  pCameraInfo->pCameraFrame=pCameraFrame;
  pCameraFrame->m_pCameraInfo=pCameraInfo;
  
  // Mark node as busy (it is definetely busy)
  EnableNode(Ix,FALSE);
}

void CDlgNodeList::OnDblclkDevices() 
{
  OnConnect();
}

void CDlgNodeList::OnOK()
{
  // Do nothing on OK
  //CDialog::OnOK();
}

void CDlgNodeList::OnCancel()
{
  // Do nothing on cancel button
  //CDialog::OnCancel();
}
